package com.lib.smartimage;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

import androidx.appcompat.widget.AppCompatImageView;

import com.layout.smart_image_view.R;
import com.lib.common.view.AutoFitImageView;
import com.lib.utils.XLog;

import java.lang.ref.WeakReference;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SmartImageView extends AppCompatImageView {
    private static final int LOADING_THREADS = 5;
    private static ExecutorService sExecutorService;

    private boolean mAsBackground;
    private ImageTask mCurrentTask;

    private Integer mFallbackResource;
    private InnerHandler mHandler;

    private boolean mAutoFit = false;

    public interface OnSuccessListener {
        boolean onSuccess(Bitmap bitmap);
    }

    public interface onFailedListener {
        void onFailed();
    }

    public SmartImageView(Context context) {
        this(context, null);
    }

    public SmartImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SmartImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SmartImageView, 0, 0);
        String url = ta.getString(R.styleable.SmartImageView_url);
        int img_width = ta.getInt(R.styleable.SmartImageView_img_width, -1);
        mAutoFit = ta.getBoolean(R.styleable.SmartImageView_auto, mAutoFit);
        mAsBackground = ta.getBoolean(R.styleable.SmartImageView_asBackground, mAsBackground);
        ta.recycle();

        if (img_width > 0 && url != null && (url.startsWith("http") || url.startsWith("HTTP"))) {
            setImage(new WebSmartImage(url, img_width));
        }
    }

    /**
     * @param url 路径
     */
    public SmartImageView setImageUrl(String url) {
        setImage(new WebSmartImage(url));
        return this;
    }

    /**
     * @param url   路径
     * @param width 需要的宽，高会自动计算
     */
    public SmartImageView setImageUrl(String url, int width) {
        setImage(new WebSmartImage(url, width));
        return this;
    }

    public void setImageContact(long contactId) {
        setImage(new ContactSmartImage(contactId));
    }

    public SmartImageView setImageListener(OnSuccessListener onSuccessListener, onFailedListener onFailedListener) {
        mHandler.mOnSuccessListener = onSuccessListener;
        mHandler.mOnFailedListener = onFailedListener;
        return this;
    }

    public SmartImageView setLoadingOrFailedRes(Integer loadingResource, Integer fallbackResource, boolean asBackground) {
        mAsBackground = asBackground;    /* Set a loading resource */
        if (loadingResource != null) {
            if (mAsBackground) {
                setBackgroundResource(loadingResource);
            } else {
                setImageResource(loadingResource);
            }
        }
        mFallbackResource = fallbackResource;
        return this;
    }

    private void setImage(ISmartImage image) {
        // Cancel any existing tasks for this image view
        if (mCurrentTask != null) {
            mCurrentTask.setCancel(true);
            mCurrentTask = null;
        }
        if (mHandler == null) {
            mHandler = new InnerHandler(this);
        }
        // Set up the new task
        mCurrentTask = new ImageTask(getContext(), image, mHandler);
        if (sExecutorService == null) {
            sExecutorService = Executors.newFixedThreadPool(LOADING_THREADS);
        }
        sExecutorService.execute(mCurrentTask);
    }

    public void setImageAsBackground(boolean asBackground) {
        mAsBackground = asBackground;
    }

    public boolean isAuto() {
        return mAutoFit;
    }

    public void setAutoFit(boolean autoFit) {
        mAutoFit = autoFit;
        requestLayout();
    }

    public static void cancelAllTasks() {
        if (sExecutorService != null) {
            try {
                sExecutorService.shutdownNow();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (!mAutoFit) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            return;
        }
        int widthMode = View.MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = View.MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = View.MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
        int heightSize = View.MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();

        Drawable drawable = getDrawable();
        if (drawable == null) {
            if (widthMode != View.MeasureSpec.EXACTLY) {
                widthSize = getSuggestedMinimumWidth();
            }
            if (heightMode != View.MeasureSpec.EXACTLY) {
                heightSize = getSuggestedMinimumHeight();
            }
        } else {
            //图片自身比例
            float ratio = (drawable.getIntrinsicWidth() / ((float) drawable.getIntrinsicHeight()));

            if (widthMode == View.MeasureSpec.EXACTLY && heightMode != View.MeasureSpec.EXACTLY) {
                // 表示宽度确定，要测量高度
                heightSize = (int) (widthSize / ratio + 0.5f);
            } else if (heightMode == View.MeasureSpec.EXACTLY && widthMode != View.MeasureSpec.EXACTLY) {
                // 表示高度确定，要测量宽度
                widthSize = (int) (heightSize * ratio + 0.5f);
            }
        }
        setMeasuredDimension(widthSize, heightSize);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();

        cancelAllTasks();
        sExecutorService = null;
        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }
    }

    public static class InnerHandler extends Handler {
        private SmartImageView mSmartImageView;
        private OnSuccessListener mOnSuccessListener;
        private onFailedListener mOnFailedListener;

        InnerHandler(SmartImageView smartImageView) {
            super(Looper.getMainLooper());
            mSmartImageView = new WeakReference<>(smartImageView).get();
        }

        @Override
        public void handleMessage(Message msg) {
            Bitmap bitmap = (Bitmap) msg.obj;
            if (bitmap == null || bitmap.getByteCount() == 0 || bitmap.isRecycled()) {
                if (mSmartImageView != null && mSmartImageView.mFallbackResource != null) {
                    if (mSmartImageView.mAsBackground) {
                        mSmartImageView.setBackgroundResource(mSmartImageView.mFallbackResource);
                    } else {
                        mSmartImageView.setImageResource(mSmartImageView.mFallbackResource);
                    }
                }

                if (mOnFailedListener != null) {
                    mOnFailedListener.onFailed();
                }
                return;
            }
            if (mOnSuccessListener != null) {
                if (!mOnSuccessListener.onSuccess(bitmap)) {
                    if (mSmartImageView != null) {
                        if (mSmartImageView.mAsBackground) {
                            mSmartImageView.setBackgroundDrawable(new BitmapDrawable(mSmartImageView.getResources(), bitmap));
                        } else {
                            mSmartImageView.setImageBitmap(bitmap);
                        }
                    }
                }
            } else if (mSmartImageView != null) {
                if (mSmartImageView.mAsBackground) {
                    mSmartImageView.setBackgroundDrawable(new BitmapDrawable(mSmartImageView.getResources(), bitmap));
                } else {
                    mSmartImageView.setImageBitmap(bitmap);
                }
            }
        }
    }

    public static class ImageTask implements Runnable {
        private ISmartImage mImage;

        private Context mContext;
        private Handler mHandler;
        private boolean mCancel;

        public ImageTask(Context context, ISmartImage image, Handler handler) {
            mContext = context;
            mImage = image;
            mHandler = handler;
        }

        @Override
        public void run() {
            if (mImage != null) {
                if (mHandler != null && !mCancel) {
                    Bitmap bitmap = mImage.getBitmap(mContext);
                    Message.obtain(mHandler, 0, bitmap).sendToTarget();
                }
            }
        }

        public void setCancel(boolean cancel) {
            mCancel = cancel;
            mImage.setCancel(cancel);
        }
    }
}